﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using yzrilyzr.util;
using Exception = System.Exception;

namespace FAQ_UI
{
	public class NinePatchDrawable : Drawable
	{
		private byte[] data;
		private int stride;
		public BitmapImage bitmap;
		public int[] ps = new int[4];
		public int[] padpos = new int[4];
		internal ImageSource[] patch = new ImageSource[9];
		internal ImageSource[] mirroredPatch = new ImageSource[9];
		private bool mMirror = false;

		public bool Mirror
		{ get { return mMirror; } set { mMirror = value; invalidateSelf(); } }

		public NinePatchDrawable(Drawable drawable)
		{
			if (drawable is BitmapDrawable)
			{
				this.bitmap = ((BitmapDrawable)drawable).bitmap;
				init();
			}
			else
			{
				Logger.getDef().i("Not BitmapDrawable");
			}
		}

		public NinePatchDrawable(byte[] data) : this(new BitmapDrawable(data))
		{
		}

		public NinePatchDrawable(BitmapImage bitmap)
		{
			this.bitmap = bitmap;
			init();
		}

		private void init()
		{
			stride = bitmap.Format.BitsPerPixel * bitmap.PixelWidth / 8;
			data = new byte[bitmap.PixelHeight * stride];
			bitmap.CopyPixels(new Int32Rect(), data, stride, 0);
			findPatch();
			generatePath();
		}

		private void generatePath()
		{
			int bw = bitmap.PixelWidth;
			int bh = bitmap.PixelHeight;
			int mg = 1;
			int x1 = mg;
			int x2 = ps[0];
			int x3 = ps[1];
			int x4 = bw - mg;
			int y1 = mg;
			int y2 = ps[2];
			int y3 = ps[3];
			int y4 = bh - mg;
			int w1 = x2 - x1;
			int w2 = x3 - x2;
			int w3 = x4 - x3;
			int h1 = y2 - y1;
			int h2 = y3 - y2;
			int h3 = y4 - y3;
			patch[0] = new CroppedBitmap(bitmap, new Int32Rect((int)x1, (int)y1, (int)w1, (int)h1));
			patch[1] = new CroppedBitmap(bitmap, new Int32Rect((int)x2, (int)y1, (int)w2, (int)h1));
			patch[2] = new CroppedBitmap(bitmap, new Int32Rect(x3, (int)y1, (int)w3, (int)h1));
			patch[3] = new CroppedBitmap(bitmap, new Int32Rect((int)x1, (int)y2, (int)w1, (int)h2));
			patch[4] = new CroppedBitmap(bitmap, new Int32Rect((int)x2, (int)y2, (int)w2, (int)h2));
			patch[5] = new CroppedBitmap(bitmap, new Int32Rect(x3, (int)y2, (int)w3, (int)h2));
			patch[6] = new CroppedBitmap(bitmap, new Int32Rect((int)x1, y3, (int)w1, (int)h3));
			patch[7] = new CroppedBitmap(bitmap, new Int32Rect((int)x2, y3, (int)w2, (int)h3));
			patch[8] = new CroppedBitmap(bitmap, new Int32Rect(x3, y3, (int)w3, (int)h3));

			int height = bitmap.PixelHeight, halfWidth = bitmap.PixelWidth / 2, width = bitmap.PixelWidth;
			byte temp;
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < halfWidth; j++)
				{
					int index1 = i * width * 4 + 4 * j;               // B
					int index2 = (i + 1) * width * 4 - (1 + j) * 4;
					temp = data[index1];
					data[index1] = data[index2];
					data[index2] = temp;
					index1 = i * width * 4 + 4 * j + 1;               // G
					index2 = (i + 1) * width * 4 - (1 + j) * 4 + 1;
					temp = data[index1];
					data[index1] = data[index2];
					data[index2] = temp;
					index1 = i * width * 4 + 4 * j + 2;               // R
					index2 = (i + 1) * width * 4 - (1 + j) * 4 + 2;
					temp = data[index1];
					data[index1] = data[index2];
					data[index2] = temp;
					index1 = i * width * 4 + 4 * j + 3;               // A
					index2 = (i + 1) * width * 4 - (1 + j) * 4 + 3;
					temp = data[index1];
					data[index1] = data[index2];
					data[index2] = temp;
				}
			}

			BitmapSource mi = BitmapSource.Create(bitmap.PixelWidth, bitmap.PixelHeight, 0, 0, PixelFormats.Bgra32, null, data, stride);
			mirroredPatch[2] = new CroppedBitmap(mi, new Int32Rect((int)width - w1 - mg, (int)y1, (int)w1, (int)h1));
			mirroredPatch[1] = new CroppedBitmap(mi, new Int32Rect((int)width - w1 - w2 - mg, (int)y1, (int)w2, (int)h1));
			mirroredPatch[0] = new CroppedBitmap(mi, new Int32Rect((int)width - w3 - w2 - w1 - mg, (int)y1, (int)w3, (int)h1));
			mirroredPatch[5] = new CroppedBitmap(mi, new Int32Rect((int)width - w1 - mg, (int)y2, (int)w1, (int)h2));
			mirroredPatch[4] = new CroppedBitmap(mi, new Int32Rect((int)width - w1 - w2 - mg, (int)y2, (int)w2, (int)h2));
			mirroredPatch[3] = new CroppedBitmap(mi, new Int32Rect((int)width - w3 - w2 - w1 - mg, (int)y2, (int)w3, (int)h2));
			mirroredPatch[8] = new CroppedBitmap(mi, new Int32Rect((int)width - w1 - mg, y3, (int)w1, (int)h3));
			mirroredPatch[7] = new CroppedBitmap(mi, new Int32Rect((int)width - w1 - w2 - mg, y3, (int)w2, (int)h3));
			mirroredPatch[6] = new CroppedBitmap(mi, new Int32Rect((int)width - w3 - w2 - w1 - mg, y3, (int)w3, (int)h3));
			data = null;
		}

		/* private static ImageSource mirror(BitmapImage imageSource)
         {
             throw new NotImplementedException();
         }*/

		/* public Thickness getPadding()
         {
             double left = (int)(padpos[0]);
             double top = (int)(padpos[2]);
             double right = (int)(padpos[1]);
             double bottom = (int)(padpos[3]);
             if (mirror) return new Thickness(right, top, left, bottom);
             return new Thickness(left, top, right, bottom);
         }*/

		public Thickness getPadding(int limit, bool mirror)
		{
			double lrp = padpos[0] + padpos[1];
			double tbp = padpos[2] + padpos[3];
			double scale = 1;
			if (lrp > limit || tbp > limit)
			{
				double max = Math.Max(lrp, tbp);
				scale = limit / max;
			}
			double left = (int)(padpos[0] * scale);
			double top = (int)(padpos[2] * scale);
			double right = (int)(padpos[1] * scale);
			double bottom = (int)(padpos[3] * scale);
			if (mirror) return new Thickness(right, top, left, bottom);
			return new Thickness(left, top, right, bottom);
		}

		private void findPatch()
		{
			double w = bitmap.PixelWidth, h = bitmap.PixelHeight;
			int state = 0;
			for (int i = 0; i < 4; i++)
			{
				ps[i] = 0;
				padpos[i] = 0;
			}
			for (int i = 0; i < w; i++)
			{
				int al = getAlphaPixel(i, 0);
				if (al > 128 && state == 0)
				{
					state = 1;
					ps[0] = i;
				}
				else if (al == 0 && state == 1)
				{
					state = 2;
					ps[1] = i;
				}
			}
			state = 0;
			for (int i = 0; i < h; i++)
			{
				int al = getAlphaPixel(0, i);
				if (al > 128 && state == 0)
				{
					state = 1;
					ps[2] = i;
				}
				else if (al == 0 && state == 1)
				{
					state = 2;
					ps[3] = i;
				}
			}
			state = 0;
			for (int i = 0; i < w; i++)
			{
				int al = getAlphaPixel(i, (int)h - 1);
				if (al > 128 && state == 0)
				{
					state = 1;
					padpos[0] = i;
				}
				else if (al == 0 && state == 1)
				{
					state = 2;
					padpos[1] = (int)w - i;
				}
			}
			state = 0;
			for (int i = 0; i < h; i++)
			{
				int al = getAlphaPixel((int)w - 1, i);
				if (al > 128 && state == 0)
				{
					state = 1;
					padpos[2] = i;
				}
				else if (al == 0 && state == 1)
				{
					state = 2;
					padpos[3] = (int)h - i;
				}
			}
		}

		private int getAlphaPixel(int x, int y)
		{
			int off = y * stride + x * 4;
			return data[off + 3];
		}

		public override void draw(DrawingContext drawingContext)
		{
			Thickness t = getPadding(70, mMirror);
			double w = bounds.Width;
			double h = bounds.Height;
			if (w == 0 || h == 0) return;
			try
			{
				if (mMirror)
				{
					drawingContext.DrawImage(mirroredPatch[0], new Rect(0, 0, t.Left + 1, t.Top + 1));
					drawingContext.DrawImage(mirroredPatch[1], new Rect(t.Left, 0, w - t.Left - t.Right + 1, t.Top + 1));
					drawingContext.DrawImage(mirroredPatch[2], new Rect(w - t.Right, 0, t.Right + 1, t.Top + 1));
					drawingContext.DrawImage(mirroredPatch[3], new Rect(0, t.Top, t.Left + 1, h - t.Top - t.Bottom + 1));
					drawingContext.DrawImage(mirroredPatch[4], new Rect(t.Left, t.Top, w - t.Left - t.Right + 1, h - t.Top - t.Bottom + 1));
					drawingContext.DrawImage(mirroredPatch[5], new Rect(w - t.Right, t.Top, t.Right + 1, h - t.Top - t.Bottom + 1));
					drawingContext.DrawImage(mirroredPatch[6], new Rect(0, h - t.Bottom, t.Left + 1, t.Bottom + 1));
					drawingContext.DrawImage(mirroredPatch[7], new Rect(t.Left, h - t.Bottom, w - t.Left - t.Right + 1, t.Bottom + 1));
					drawingContext.DrawImage(mirroredPatch[8], new Rect(w - t.Right, h - t.Bottom, t.Right + 1, t.Bottom + 1));
				}
				else
				{
					drawingContext.DrawImage(patch[0], new Rect(0, 0, t.Left + 1, t.Top + 1));
					drawingContext.DrawImage(patch[1], new Rect(t.Left, 0, w - t.Left - t.Right + 1, t.Top + 1));
					drawingContext.DrawImage(patch[2], new Rect(w - t.Right, 0, t.Right + 1, t.Top + 1));
					drawingContext.DrawImage(patch[3], new Rect(0, t.Top, t.Left + 1, h - t.Top - t.Bottom + 1));
					drawingContext.DrawImage(patch[4], new Rect(t.Left, t.Top, w - t.Left - t.Right + 1, h - t.Top - t.Bottom + 1));
					drawingContext.DrawImage(patch[5], new Rect(w - t.Right, t.Top, t.Right + 1, h - t.Top - t.Bottom + 1));
					drawingContext.DrawImage(patch[6], new Rect(0, h - t.Bottom, t.Left + 1, t.Bottom + 1));
					drawingContext.DrawImage(patch[7], new Rect(t.Left, h - t.Bottom, w - t.Left - t.Right + 1, t.Bottom + 1));
					drawingContext.DrawImage(patch[8], new Rect(w - t.Right, h - t.Bottom, t.Right + 1, t.Bottom + 1));
				}
			}
			catch (Exception)
			{
				Logger.getDef().i("RenderSize Err");
			}
		}
	}
}